home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UFatalError.cp < prev    next >
Encoding:
Text File  |  1994-03-16  |  7.5 KB  |  330 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993 Peter Speck (speck@dat.ruc.dk).  All rights reserved.
  2. // UFatalError.cp
  3.  
  4. #include "UFatalError.h"
  5. #include "Tools.h"
  6. #include "FileTools.h"
  7. #include "UThread.h"
  8.  
  9. #include <RsrcGlobals.h>
  10. #include <ErrorGlobals.h>
  11.  
  12. #include <ToolUtils.h>
  13. #include <OSUtils.h>
  14. #include <Packages.h>
  15. #include <Resources.h>
  16. #include <GestaltEqu.h>
  17. #include <Folders.h>
  18. #include <Unmangler.h>
  19. #include <DisAsmLookup.h>
  20. #ifndef __STDIO__
  21. #include <stdio.h>
  22. #endif
  23.  
  24. #pragma segment MyTools
  25.  
  26. Handle gFatalErrorReserveH = nil;
  27.  
  28. char gPanicBuffer[kPanicBufferSize + 100];
  29.  
  30. void ReallocFatalErrorReserve()
  31. {
  32.     if (gFatalErrorReserveH)
  33.         return;
  34.     long size = 5 * 1024;
  35.     while (size)
  36.     {
  37.         gFatalErrorReserveH = NewHandle(size);
  38.         if (gFatalErrorReserveH)
  39.             return;
  40.         size -= 1 * 1024;
  41.     }
  42. }
  43.  
  44. void InitUFatalError()
  45. {
  46.     gFatalErrorReserveH = NewPermHandle(5 * 1024);
  47. }
  48.  
  49. void AppendLineToErrorFile(const CStr255 &msg)
  50. {
  51.     CStr255 s(msg);
  52.     if (!s.Length() || s[s.Length()] != 13)
  53.         s += 13;
  54.     fprintf(stderr, "%s", (char*)s);
  55. }
  56.  
  57. void MyGetFunctionName(void* pc, CStr255 &name)
  58. {
  59.     if (pc != NULL && !odd(long(pc)))
  60.     {
  61.         void* nextPC;
  62.         CStr255 localname;
  63.         Ptr limit = Ptr(ptrdiff_t(pc) + 32767);
  64.         while (!endOfModule(pc, limit, (char *) &localname, &nextPC))
  65.         {
  66.             if (pc >= limit)
  67.             {
  68.                 name = "";
  69.                 localname = "";
  70.                 return;
  71.             }
  72.             else
  73.                 pc = (void *) (ptrdiff_t(pc) + 2);
  74.         }
  75.  
  76.         char cname[256];
  77.  
  78.         if (unmangle(cname, (char *) localname, 255) < 1)
  79.             name = localname;
  80.         else
  81.             name = cname;
  82.         short index = name.Pos(".");
  83.     }
  84.     else
  85.     {
  86.         name = "";
  87.     }
  88. }
  89.  
  90. void DebugFrameFindReturnOffset(void *pc)
  91. {
  92.     long numIter = 0;
  93.     short *wp = (short*)pc;
  94.     if (long(wp) & 1) // odd address
  95.         return;
  96.     while (true)
  97.     {
  98.         if (++numIter > 1000)
  99.             return;
  100.         // avoid the constant 0x4E56 (LINK A6,#) in code as Macsbug doesn't like it,
  101.         // just like this little function
  102.         if (*wp - 6 == 0x4E50) 
  103.             break;
  104.         wp--;
  105.     }
  106.     fprintf(stderr, " + $%lx", long(pc) - long(wp));
  107. }
  108.  
  109. void *gNextA6;
  110. CStr255 procName;
  111. void DumpFrame()
  112. {
  113.     if (odd(long(gNextA6)) ||
  114.                 gNextA6 > GetCurStackBase() ||
  115.                 gNextA6 < GetCurStackTop())
  116.         return; // CStackFrame::LooksValid() inverted
  117.     void *pc = *(void **) (long(gNextA6) + 4); // CStackFrame::GetReturnAddress
  118.     if (odd(long(pc)))
  119.         return;
  120.     gNextA6 = *((void **) gNextA6);
  121.     DumpFrame();
  122.     MyGetFunctionName(pc, procName);
  123.     fprintf(stderr, "      %s", (char*)procName);
  124.     DebugFrameFindReturnOffset(pc);
  125.     fprintf(stderr, "\n");
  126. }
  127.  
  128. void DumpStack()
  129. {
  130.     fprintf(stderr, "Dumping stack\n");
  131.     gNextA6 = GetCurStackFramePtr();
  132.     DumpFrame();
  133.     fprintf(stderr, "End of stack dump, size ~ %ld\n", long(GetCurStackBase()) - long(GetCurStackFramePtr()));    
  134. }
  135.  
  136. void DoFatalError(const char *fatalMsg, Boolean abort)
  137. {
  138.     gFatalErrorReserveH = DisposeIfHandle(gFatalErrorReserveH);
  139. #if !qDebug & 0
  140.     if (logf)
  141.         fclose(logf);
  142. #endif
  143. #if qDebug
  144.     fprintf(stderr, "\n");
  145.     fprintf(stderr, "Fatal error:\n");
  146.     static char buffer[3000];
  147.     strcpy(buffer, fatalMsg);
  148.     Ptr start = buffer;
  149.     while (*start)
  150.     {
  151.         Ptr p = start;
  152.         while (*p && *p != 13) ++p;
  153.         Boolean atEnd = (*p == 0);
  154.         *p = 0;
  155.         fprintf(stderr, "%s\n", start);
  156.         if (atEnd)
  157.             break;
  158.         start = p + 1;
  159.     }
  160.     ProgramBreak(gEmptyString);
  161. #endif
  162.     unsigned long tc = TickCount();
  163.     unsigned long dt;
  164.     GetDateTime(dt);
  165.  
  166.     FlushVols();
  167.     if (abort)
  168.     {
  169.         FreeIfObject(gBusyCursor); gBusyCursor = nil; // stop spinning cursor
  170.         UnpatchAll();
  171.     }
  172.     UseResFile(gApplicationRefNum);
  173.  
  174.     FailInfo fi;
  175.     if (fi.Try())
  176.     {
  177.         CStr255 s, msg, repl;
  178.         long resp, li;
  179.     
  180. // alert
  181.         MAInteractWithUser(kNoTimeOut, gNotificationPtr, nil);
  182.         SetCursor(qd.arrow);
  183.         if (abort)
  184.             Alert(phPanicExitAlert, nil);
  185.         else
  186.             Alert(phFatalReportAlert, nil);
  187.  
  188. //    create bug file
  189.         FSSpec spec;
  190.         FailOSErr(FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, spec.vRefNum, spec.parID));
  191.         MyGetIndString(s, kErrorFileName);
  192.         CopyCString2String(s, spec.name);
  193.         MakeFilenameUnique(spec);
  194.         GetPathNameFromDirID(spec.vRefNum, spec.parID, msg);
  195.         msg += CStr255(spec.name);
  196. #if qDebug
  197.         fprintf(stderr, "Filename for FatalErrorMsg: '%s'\n", (char*)msg);
  198. #endif
  199.         FILE oldStdErr = *stderr;
  200.         FILE *file = fopen(msg, "w+");
  201.         if (!file)
  202.         {
  203.             for (li = 1; li <= 6; li++)
  204.                 SysBeep(1);
  205.             FlushVols();
  206.             ExitToShell();
  207.         }
  208.         fsetfileinfo(msg, 'ttxt', 'TEXT');
  209. //        file = fopen(msg, "a");
  210.         _iob[2] = *file;  // _iob[2] = stderr
  211.  
  212. // initial message
  213.         MyGetIndString(msg, kFEInitialMessage);
  214.         AppendLineToErrorFile(msg);
  215.         
  216. // Error description
  217.         MyGetIndString(msg, kFEErrorMessage);
  218.         AppendLineToErrorFile(msg);
  219.         fputs(fatalMsg, stderr);
  220.         fprintf(stderr, "\n\n");
  221.  
  222. // Nuntius version
  223.         VersRecHndl vH = nil;
  224.         vH = VersRecHndl(GetResource('vers', 1));
  225.         if (vH != nil)
  226.         {
  227.             MyGetIndString(msg, kFEVersion1);
  228.             repl = (*vH)->shortVersion;
  229.             SubstituteStringItems(msg, "«version»", repl);
  230.             if ((*vH)->countryCode == 0)
  231.                 MyGetIndString(repl, kFEUSLangName);
  232.             else
  233.                 NumToString((*vH)->countryCode, repl);
  234.             SubstituteStringItems(msg, "«language»", repl);
  235.             AppendLineToErrorFile(msg);
  236.         }    
  237.         vH = VersRecHndl(GetResource('vers', 2));
  238.         if (vH != nil)
  239.         {
  240.             MyGetIndString(msg, kFEVersion2);
  241.             repl = (*vH)->shortVersion;
  242.             SubstituteStringItems(msg, "«version»", repl);
  243.             if ((*vH)->countryCode == 0)
  244.                 MyGetIndString(repl, kFEUSLangName);
  245.             else
  246.                 NumToString((*vH)->countryCode, repl);
  247.             SubstituteStringItems(msg, "«language»", repl);
  248.             AppendLineToErrorFile(msg);
  249.         }
  250.         MyGetIndString(msg, kFECompileDateString);
  251.         AppendLineToErrorFile(msg);
  252.     
  253. // Time for error
  254.         fprintf(stderr, "Tidspunkt:\n");
  255.         fprintf(stderr, "  TickCount() = %ld\n", tc);
  256.         IUDateString(dt, longDate, s);
  257.         IUTimeString(dt, true, msg);
  258.         fprintf(stderr, "   %s  ", (char*)s);
  259.         fprintf(stderr, "   %s\n", (char*)msg);
  260.  
  261. // HeaderBodySeparator
  262.         MyGetIndString(msg, kFEHeaderBodySeparator);
  263.         AppendLineToErrorFile(msg);
  264.  
  265. // Free memory
  266.         long total, contig;
  267.         PurgeSpace(total, contig);
  268.         fprintf(stderr, "Free memory: %ld  (largest block: %ld)\n", total, contig);
  269.         Size szCodeReserve, szMemReserve;
  270.         GetReserveSize(szCodeReserve, szMemReserve);
  271.         li = (pCodeReserve && *pCodeReserve) ? GetHandleSize(pCodeReserve) : 0;
  272.         fprintf(stderr, "  - pSzCodeReserve = %ld, pCodeReserveSize = %ld\n", szCodeReserve, li);
  273.         li = (pMemReserve && *pMemReserve) ? GetHandleSize(pMemReserve) : 0;
  274.         fprintf(stderr, "  - pSzMemReserve  = %ld, pMemReserveSize = %ld\n", szMemReserve, li);
  275.         li = (pMemReserve && *pMemReserve) ? GetHandleSize(pMemReserve) : 0;
  276.         fprintf(stderr, "  - pOKCodeReserve = %ld, pReserveExists = %ld, MemSpaceIsLow() = %ld\n", long(pOKCodeReserve), long(pReserveExists), long(MemSpaceIsLow()));
  277.  
  278. // Machine type
  279.         Gestalt(gestaltMachineType, resp);
  280.         GetIndString(repl, kMachineNameStrID, short(resp));
  281.         MyGetIndString(msg, kFEMacModel);
  282.         SubstituteStringItems(msg, "«macmodel»", repl);
  283.         AppendLineToErrorFile(msg);
  284.  
  285. // system version
  286.         Gestalt(gestaltSystemVersion, resp);
  287.         VersionToString(resp, repl);
  288.         MyGetIndString(msg, kFESystemVersion);
  289.         SubstituteStringItems(msg, "«sysversion»", repl);
  290.         AppendLineToErrorFile(msg);
  291.  
  292. // Threads
  293.         DumpDebugThreadDescription();
  294.         
  295. // Stack crawl
  296.         DumpStack();
  297.         
  298. // done
  299.         MyGetIndString(msg, kFEPostMessage);
  300.         AppendLineToErrorFile(msg);
  301.         fclose(stderr);
  302.         *stderr = oldStdErr;
  303.         FlushVols();
  304.         if (abort)
  305.         {
  306.             ExitToShell();
  307.             // report a fatal error here?
  308.         }
  309.         ReallocFatalErrorReserve();
  310.         fi.Success();
  311.     }
  312.     else // fail, ups
  313.     {
  314.         for (short i = 1; i <= 10; i++)
  315.             SysBeep(1);
  316.         ExitToShell();
  317.         fi.ReSignal(); // what else?
  318.     }
  319. }
  320.  
  321. void PanicExitToShell(const char *fatalMsg)
  322. {
  323.     DoFatalError(fatalMsg, true);
  324. }
  325.  
  326. void ReportFatalError(const char *fatalMsg)
  327. {
  328.     DoFatalError(fatalMsg, false);
  329. }
  330.